import json
import os
import shutil
import tornado
from tornado import gen
from tornado import web

import sys
sys.path.append("..")

from .base import BaseHandler
from utils.jsonresult import JsonResult, json_result_encoder
from utils.pathutil import PathBuilder

class LabStorageHandler(BaseHandler):
    @web.authenticated
    @gen.coroutine
    def post(self):        
        request_data = json.loads(self.request.body.decode())
        account_name = request_data.get('accountname')
        root_path = PathBuilder.get_labs_dir_for_student(account_name)
        sub_path = request_data.get('path')
        operation = request_data.get('operation')
        operand = request_data.get('operand')

        json_result = JsonResult()

        call_func = dispatch_map.get(operation)
        if call_func is None:
            json_result.message = '无效的操作'
        else:
            call_func(root_path, sub_path, operand, json_result)

        self.write(json.dumps(json_result, ensure_ascii=True, default=json_result_encoder))
        self.finish() 
    
    # 从标准库中装载实验文件到学生的实验目录中
    @staticmethod
    def load_lab_files(root_path, sub_path, operand, json_result):
        source_dir = PathBuilder.get_library_dir_for_lab(sub_path)
        if not os.path.exists(source_dir):
            json_result.success = False
            json_result.message = '错误的实验路径'
            return
        
        target_dir = os.path.join(root_path, sub_path)

        try:
            # 先删除目标目录(shutil.copytree必须保证目标目录是不存在的)
            if os.path.exists(target_dir):
                shutil.rmtree(target_dir)

            # 目录整体拷贝
            shutil.copytree(source_dir, target_dir)
            
            # 将拷贝后的所有目录和文件的所有者更改为data_root_owner指定的账户
            # data_root_owner = tornado.options.options.data_root_owner
            # os.system('chown -R ' + data_root_owner + ' ' + target_dir)
        except:
            json_result.success = False
            json_result.message = '装载实验文件失败'
        

    # 获取特定学生特定Lab下的所有一级文件和子目录
    @staticmethod
    def list_items(root_path, sub_path, operand, json_result):
        full_dir_path = os.path.join(root_path, sub_path)
        if not os.path.isdir(full_dir_path):
            json_result.success = False
            json_result.message = '错误的目录路径'
            return

        data_items = []
        for item in os.listdir(full_dir_path):
            data_item = {
                'name':item, 
                'path':os.path.join(sub_path, item), 
                'isdir':os.path.isdir(os.path.join(full_dir_path, item))
            }
            data_items.append(data_item)

        json_result.data = data_items


    # 获取被允许的文件后缀名列表
    @staticmethod
    def allowed_file_types(root_path, sub_path, operand, json_result):
        json_result.data = tornado.options.options.allowed_customized_file_types


# 处理实验打包下载
class DownloadLabFilesHandler(BaseHandler):
    @web.authenticated
    @gen.coroutine
    def get(self):
        account_name = self.get_argument('accountname','')
        lab_code = self.get_argument('labcode','')
        root_path = PathBuilder.get_labs_dir_for_student(account_name)
        lab_full_path = os.path.join(root_path, lab_code)
        
        shutil.make_archive(lab_full_path, 'zip', lab_full_path)
        zip_filepath = lab_full_path + ".zip"
        
        self.set_header ('Content-Type', 'application/octet-stream')
        self.set_header ('Content-Disposition', 'attachment; filename=' + lab_code + ".zip")
        buf_size = 8192
        with open(zip_filepath, 'rb') as f:
            while True:
                data = f.read(buf_size)
                if not data:
                    break
                self.write(data)
        # 删除zip包
        os.remove(zip_filepath)

        self.finish()

dispatch_map = {
    'load_lab_files' : LabStorageHandler.load_lab_files,
    'list_items': LabStorageHandler.list_items,
    'allowed_file_types' : LabStorageHandler.allowed_file_types
}

default_handlers = [
    (r'/labstorage', LabStorageHandler),
    (r'/labstorage_download', DownloadLabFilesHandler)
]